package com.ryder.petmatediarybackend.module.pet.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ryder.petmatediarybackend.common.enums.ResultCode;
import com.ryder.petmatediarybackend.common.enums.RoleLevelEnum;
import com.ryder.petmatediarybackend.common.exception.BusinessException;
import com.ryder.petmatediarybackend.module.auth.dto.RegisterDTO;
import com.ryder.petmatediarybackend.module.auth.entity.SysRole;
import com.ryder.petmatediarybackend.module.auth.service.SysRolePermissionService;
import com.ryder.petmatediarybackend.module.auth.service.SysRoleService;
import com.ryder.petmatediarybackend.module.auth.service.SysUserRoleService;
import com.ryder.petmatediarybackend.module.auth.vo.UserVO;
import com.ryder.petmatediarybackend.module.pet.entity.PetProfile;
import com.ryder.petmatediarybackend.module.pet.entity.SysUser;
import com.ryder.petmatediarybackend.module.pet.mapper.SysUserMapper;
import com.ryder.petmatediarybackend.module.pet.service.PetProfileService;
import com.ryder.petmatediarybackend.module.pet.service.SysUserService;
import com.ryder.petmatediarybackend.module.social.entity.SocialPost;
import com.ryder.petmatediarybackend.module.social.mapper.SocialPostMapper;
import com.ryder.petmatediarybackend.module.user.dto.ChangePasswordDTO;
import com.ryder.petmatediarybackend.module.user.dto.UpdateProfileDTO;
import com.ryder.petmatediarybackend.module.user.entity.SysUserProfile;
import com.ryder.petmatediarybackend.module.user.service.SysUserProfileService;
import com.ryder.petmatediarybackend.module.user.vo.UserProfileVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 描述: 系统用户表(SysUser)表服务实现类
 * 
 * @author Ryder
 * @version 1.0
 * @since 1.0
 * 更新日期: 2025-10-31 08:00:00
 */
@Slf4j
@Service("sysUserService")
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private final PasswordEncoder passwordEncoder;

    private final SysRoleService sysRoleService;

    private final SysUserRoleService sysUserRoleService;

    private final SysRolePermissionService sysRolePermissionService;

    private final SysUserProfileService sysUserProfileService;

    private final PetProfileService petProfileService;

    private final SocialPostMapper socialPostMapper;

    private final ObjectMapper objectMapper;

    @Override
    public SysUser getUserByUsername(String username) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, username);
        return this.getOne(wrapper);
    }

    @Override
    public boolean existsByUsername(String username) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, username);
        return this.count(wrapper) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserVO createUser(RegisterDTO dto) {
        // 1. 校验用户名是否已存在
        if (existsByUsername(dto.getUsername())) {
            throw new BusinessException(ResultCode.USERNAME_EXISTS);
        }

        // 2. 创建用户实体
        SysUser user = new SysUser();
        user.setUsername(dto.getUsername());
        user.setPasswordHash(passwordEncoder.encode(dto.getPassword()));
        user.setNickname(dto.getNickname() != null ? dto.getNickname() : dto.getUsername());
        user.setEmail(dto.getEmail());
        user.setPhone(dto.getPhone());
        user.setStatus(1); // 默认启用
        user.setRegisterIp("127.0.0.1"); // TODO: 从 Request 中获取真实 IP

        // 3. 保存用户（MyBatis-Plus 自动生成雪花ID）
        this.save(user);

        // 4. 绑定默认角色（宠物主人，roleType=1）
        SysRole petOwnerRole = sysRoleService.getByCode(RoleLevelEnum.PET_OWNER.getRoleCode());
        if (petOwnerRole != null) {
            sysUserRoleService.bindUserRole(user.getId(), petOwnerRole.getId());
        }

        // 5. 转换为 UserVO 返回
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);
        
        // 6. 查询用户角色
        vo.setRoles(sysRolePermissionService.getUserRoles(user.getId()));

        return vo;
    }

    @Override
    public UserProfileVO getUserProfile(Long userId) {
        log.info("[用户服务] 获取用户详细信息, userId={}", userId);

        // 1. 查询用户基本信息
        SysUser user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 2. 查询用户扩展信息
        LambdaQueryWrapper<SysUserProfile> profileWrapper = new LambdaQueryWrapper<>();
        profileWrapper.eq(SysUserProfile::getUserId, userId);
        SysUserProfile userProfile = sysUserProfileService.getOne(profileWrapper);

        // 3. 构建 VO
        UserProfileVO vo = new UserProfileVO();
        BeanUtils.copyProperties(user, vo);

        if (userProfile != null) {
            vo.setBio(userProfile.getBio());
            vo.setGender(userProfile.getGender());
            vo.setBirthday(userProfile.getBirthday());

            // 解析 JSON 字段
            try {
                if (userProfile.getHobbies() != null) {
                    vo.setHobbies(objectMapper.readValue(userProfile.getHobbies(),
                            objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)));
                }
                if (userProfile.getTags() != null) {
                    vo.setTags(objectMapper.readValue(userProfile.getTags(),
                            objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)));
                }
                if (userProfile.getAvatarAlbum() != null) {
                    vo.setAvatarAlbum(objectMapper.readValue(userProfile.getAvatarAlbum(),
                            objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)));
                }
            } catch (JsonProcessingException e) {
                log.error("[用户服务] 解析JSON字段失败, userId={}", userId, e);
            }
        }

        // 4. 查询用户角色
        List<String> roles = sysRolePermissionService.getUserRoles(userId);
        vo.setRoles(roles);

        // 5. 统计数据
        LambdaQueryWrapper<PetProfile> petWrapper = new LambdaQueryWrapper<>();
        petWrapper.eq(PetProfile::getUserId, userId);
        vo.setPetCount((int) petProfileService.count(petWrapper));

        LambdaQueryWrapper<SocialPost> postWrapper = new LambdaQueryWrapper<>();
        postWrapper.eq(SocialPost::getUserId, userId);
        vo.setPostCount(socialPostMapper.selectCount(postWrapper).intValue());

        log.info("[用户服务] 获取用户详细信息成功, userId={}, petCount={}, postCount={}",
                userId, vo.getPetCount(), vo.getPostCount());

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserProfile(Long userId, UpdateProfileDTO dto) {
        log.info("[用户服务] 更新用户信息, userId={}, dto={}", userId, dto);

        // 1. 更新用户基本信息
        SysUser user = new SysUser();
        user.setId(userId);
        user.setNickname(dto.getNickname());
        user.setEmail(dto.getEmail());
        user.setPhone(dto.getPhone());
        this.updateById(user);

        // 2. 查询或创建用户扩展信息
        LambdaQueryWrapper<SysUserProfile> profileWrapper = new LambdaQueryWrapper<>();
        profileWrapper.eq(SysUserProfile::getUserId, userId);
        SysUserProfile userProfile = sysUserProfileService.getOne(profileWrapper);

        boolean isNew = false;
        if (userProfile == null) {
            userProfile = new SysUserProfile();
            userProfile.setUserId(userId);
            isNew = true;
        }

        // 3. 更新扩展信息
        userProfile.setBio(dto.getBio());
        userProfile.setGender(dto.getGender());
        userProfile.setBirthday(dto.getBirthday());

        // 序列化 JSON 字段
        try {
            if (dto.getHobbies() != null) {
                userProfile.setHobbies(objectMapper.writeValueAsString(dto.getHobbies()));
            }
            if (dto.getTags() != null) {
                userProfile.setTags(objectMapper.writeValueAsString(dto.getTags()));
            }
        } catch (JsonProcessingException e) {
            log.error("[用户服务] 序列化JSON字段失败, userId={}", userId, e);
            throw new BusinessException(ResultCode.INTERNAL_SERVER_ERROR, "数据序列化失败");
        }

        if (isNew) {
            sysUserProfileService.save(userProfile);
        } else {
            sysUserProfileService.updateById(userProfile);
        }

        log.info("[用户服务] 更新用户信息成功, userId={}", userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAvatar(Long userId, String avatarUrl) {
        log.info("[用户服务] 更新用户头像, userId={}, avatarUrl={}", userId, avatarUrl);

        SysUser user = new SysUser();
        user.setId(userId);
        user.setAvatar(avatarUrl);
        this.updateById(user);

        log.info("[用户服务] 更新用户头像成功, userId={}", userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changePassword(Long userId, ChangePasswordDTO dto) {
        log.info("[用户服务] 修改密码, userId={}", userId);

        // 1. 校验新密码和确认密码是否一致
        if (!dto.getNewPassword().equals(dto.getConfirmPassword())) {
            throw new BusinessException(ResultCode.BAD_REQUEST, "两次输入的新密码不一致");
        }

        // 2. 查询用户
        SysUser user = this.getById(userId);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }

        // 3. 校验旧密码
        if (!passwordEncoder.matches(dto.getOldPassword(), user.getPasswordHash())) {
            throw new BusinessException(ResultCode.BAD_REQUEST, "旧密码不正确");
        }

        // 4. 更新密码
        SysUser updateUser = new SysUser();
        updateUser.setId(userId);
        updateUser.setPasswordHash(passwordEncoder.encode(dto.getNewPassword()));
        this.updateById(updateUser);

        log.info("[用户服务] 修改密码成功, userId={}", userId);
    }
}
